{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Adding Model Predictions to Datasets\n",
    "\n",
    "This recipe provides a glimpse into the possibilities for integrating FiftyOne into your machine learning workflows.\n",
    "\n",
    "It covers the following concepts:\n",
    "\n",
    "-   Loading your existing dataset in FiftyOne\n",
    "-   Adding predictions from your model to your FiftyOne dataset\n",
    "-   Launching the FiftyOne App and visualizing/exploring your data\n",
    "-   Integrating the App into your data wrangling workflow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup\n",
    "\n",
    "Install `torch` and `torchvision`, if necessary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Modify as necessary (e.g., GPU install). See https://pytorch.org for options\n",
    "!pip install torch\n",
    "!pip install torchvision"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Download the test split of the CIFAR-10 dataset to `~/fiftyone/cifar10/test`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Downloads the test split of CIFAR-10\n",
    "!fiftyone zoo download cifar10 --splits test"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Download a pretrained CIFAR-10 PyTorch model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cloning into 'PyTorch_CIFAR10'...\n",
      "remote: Enumerating objects: 9, done.\u001b[K\n",
      "remote: Counting objects: 100% (9/9), done.\u001b[K\n",
      "remote: Compressing objects: 100% (7/7), done.\u001b[K\n",
      "remote: Total 560 (delta 2), reused 4 (delta 2), pack-reused 551\u001b[K\n",
      "Receiving objects: 100% (560/560), 6.55 MiB | 13.01 MiB/s, done.\n",
      "Resolving deltas: 100% (184/184), done.\n",
      "Downloading '1dGfpeFK_QG0kV-U6QDHMX2EOGXPqaNzu' to 'PyTorch_CIFAR10/cifar10_models/state_dicts/resnet50.pt'\n",
      " 100% |████|  719.8Mb/719.8Mb [8.0s elapsed, 0s remaining, 47.7Mb/s]       \n"
     ]
    }
   ],
   "source": [
    "# Download the software\n",
    "!git clone https://github.com/huyvnphan/PyTorch_CIFAR10\n",
    "\n",
    "# Download the pretrained model (90MB)\n",
    "!eta gdrive download --public \\\n",
    "    1dGfpeFK_QG0kV-U6QDHMX2EOGXPqaNzu \\\n",
    "    PyTorch_CIFAR10/cifar10_models/state_dicts/resnet50.pt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Importing FiftyOne\n",
    "\n",
    "Let's start by importing the FiftyOne library:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import fiftyone as fo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loading an image classification dataset\n",
    "\n",
    "Suppose you have an image classification dataset on disk in the following\n",
    "format:\n",
    "\n",
    "```\n",
    "<dataset_dir>/\n",
    "    data/\n",
    "        <uuid1>.<ext>\n",
    "        <uuid2>.<ext>\n",
    "        ...\n",
    "    labels.json\n",
    "```\n",
    "\n",
    "where `labels.json` is a JSON file in the following format:\n",
    "\n",
    "```\n",
    "{\n",
    "    \"classes\": [\n",
    "        <labelA>,\n",
    "        <labelB>,\n",
    "        ...\n",
    "    ],\n",
    "    \"labels\": {\n",
    "        <uuid1>: <target1>,\n",
    "        <uuid2>: <target2>,\n",
    "        ...\n",
    "    }\n",
    "}\n",
    "```\n",
    "\n",
    "In your current workflow, you may parse this data into a list of\n",
    "`(image_path, label)` tuples as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('/Users/Brian/fiftyone/cifar10/test/data/000001.jpg', 'cat'), ('/Users/Brian/fiftyone/cifar10/test/data/000002.jpg', 'ship'), ('/Users/Brian/fiftyone/cifar10/test/data/000003.jpg', 'ship'), ('/Users/Brian/fiftyone/cifar10/test/data/000004.jpg', 'airplane'), ('/Users/Brian/fiftyone/cifar10/test/data/000005.jpg', 'frog')]\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "import os\n",
    "\n",
    "# The location of the dataset on disk that you downloaded above\n",
    "dataset_dir = os.path.expanduser(\"~/fiftyone/cifar10/test\")\n",
    "\n",
    "# Maps image UUIDs to image paths\n",
    "images_dir = os.path.join(dataset_dir, \"data\")\n",
    "image_uuids_to_paths = {\n",
    "    os.path.splitext(n)[0]: os.path.join(images_dir, n)\n",
    "    for n in os.listdir(images_dir)\n",
    "}\n",
    "\n",
    "labels_path = os.path.join(dataset_dir, \"labels.json\")\n",
    "with open(labels_path, \"rt\") as f:\n",
    "    _labels = json.load(f)\n",
    "\n",
    "# Get classes\n",
    "classes = _labels[\"classes\"]\n",
    "\n",
    "# Maps image UUIDs to int targets\n",
    "labels = _labels[\"labels\"]\n",
    "\n",
    "# Make a list of (image_path, label) samples\n",
    "data = [(image_uuids_to_paths[u], classes[t]) for u, t in labels.items()]\n",
    "\n",
    "# Print a few data\n",
    "print(data[:5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Building a FiftyOne dataset from your samples is simple:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 100% |███| 10000/10000 [3.7s elapsed, 0s remaining, 2.7K samples/s]      \n",
      "Name:           my-dataset\n",
      "Persistent:     False\n",
      "Num samples:    10000\n",
      "Tags:           []\n",
      "Sample fields:\n",
      "    filepath:     fiftyone.core.fields.StringField\n",
      "    tags:         fiftyone.core.fields.ListField(fiftyone.core.fields.StringField)\n",
      "    metadata:     fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.metadata.Metadata)\n",
      "    ground_truth: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.labels.Classification)\n"
     ]
    }
   ],
   "source": [
    "# Load the data into FiftyOne samples\n",
    "samples = []\n",
    "for image_path, label in data:\n",
    "    samples.append(\n",
    "        fo.Sample(\n",
    "            filepath=image_path,\n",
    "            ground_truth=fo.Classification(label=label),\n",
    "        )\n",
    "    )\n",
    "\n",
    "# Add the samples to a dataset\n",
    "dataset = fo.Dataset(\"my-dataset\")\n",
    "dataset.add_samples(samples)\n",
    "\n",
    "# Print some information about the dataset\n",
    "print(dataset)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454930',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000001.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'cat', 'confidence': None, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454931',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000002.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'ship', 'confidence': None, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454932',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000003.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'ship', 'confidence': None, 'logits': None}>,\n",
      "}>\n"
     ]
    }
   ],
   "source": [
    "# Print a few samples from the dataset\n",
    "print(dataset.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Working with views into your dataset\n",
    "\n",
    "FiftyOne provides a powerful notion of _dataset views_ for you to access\n",
    "subsets of the samples in your dataset.\n",
    "\n",
    "Here's an example operation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset:        my-dataset\n",
      "Num samples:    5\n",
      "Tags:           []\n",
      "Sample fields:\n",
      "    filepath:     fiftyone.core.fields.StringField\n",
      "    tags:         fiftyone.core.fields.ListField(fiftyone.core.fields.StringField)\n",
      "    metadata:     fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.metadata.Metadata)\n",
      "    ground_truth: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.labels.Classification)\n",
      "Pipeline stages:\n",
      "    1. Match(filter={'$expr': {'$eq': [...]}})\n",
      "    2. Limit(limit=5)\n"
     ]
    }
   ],
   "source": [
    "# Used to write view expressions that involve sample fields\n",
    "from fiftyone import ViewField as F\n",
    "\n",
    "# Gets five airplanes from the dataset\n",
    "view = (\n",
    "    dataset.match(F(\"ground_truth.label\") == \"airplane\")\n",
    "    .limit(5)\n",
    ")\n",
    "\n",
    "# Print some information about the view you created\n",
    "print(view)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454933',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000004.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'airplane', 'confidence': None, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f45493a',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000011.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'airplane', 'confidence': None, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454945',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000022.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'airplane', 'confidence': None, 'logits': None}>,\n",
      "}>\n"
     ]
    }
   ],
   "source": [
    "# Print a few samples from the view\n",
    "print(view.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Iterating over the samples in a view is easy:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/Users/Brian/fiftyone/cifar10/test/data/000004.jpg\n",
      "/Users/Brian/fiftyone/cifar10/test/data/000011.jpg\n",
      "/Users/Brian/fiftyone/cifar10/test/data/000022.jpg\n",
      "/Users/Brian/fiftyone/cifar10/test/data/000028.jpg\n",
      "/Users/Brian/fiftyone/cifar10/test/data/000045.jpg\n"
     ]
    }
   ],
   "source": [
    "for sample in view:\n",
    "    print(sample.filepath)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding model predictions to your dataset\n",
    "\n",
    "The following code demonstrates how to add predictions from a model to your\n",
    "FiftyOne dataset, with minimal changes to your existing ML code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454e41',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/001298.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'bird', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': <Classification: {'label': 'bird', 'confidence': 0.52449214, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd82dfebeb022f45546e',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/002879.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'cat', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': <Classification: {'label': 'dog', 'confidence': 0.54008263, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd82dfebeb022f4555e1',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/003250.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'cat', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': <Classification: {'label': 'deer', 'confidence': 0.23658535, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd82dfebeb022f4555f5',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/003270.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'horse', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': <Classification: {'label': 'horse', 'confidence': 0.8297524, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd84dfebeb022f456764',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/007733.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'horse', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': <Classification: {'label': 'truck', 'confidence': 0.47881564, 'logits': None}>,\n",
      "}>\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "import numpy as np\n",
    "import torch\n",
    "import torchvision\n",
    "from torch.utils.data import DataLoader\n",
    "\n",
    "import fiftyone.utils.torch as fout\n",
    "\n",
    "sys.path.insert(1, \"PyTorch_CIFAR10\")\n",
    "from cifar10_models import *\n",
    "\n",
    "\n",
    "def make_cifar10_data_loader(image_paths, sample_ids, batch_size):\n",
    "    mean = [0.4914, 0.4822, 0.4465]\n",
    "    std = [0.2023, 0.1994, 0.2010]\n",
    "    transforms = torchvision.transforms.Compose(\n",
    "        [\n",
    "            torchvision.transforms.ToTensor(),\n",
    "            torchvision.transforms.Normalize(mean, std),\n",
    "        ]\n",
    "    )\n",
    "    dataset = fout.TorchImageDataset(\n",
    "        image_paths, sample_ids=sample_ids, transform=transforms\n",
    "    )\n",
    "    return DataLoader(dataset, batch_size=batch_size, num_workers=4)\n",
    "\n",
    "\n",
    "def predict(model, imgs):\n",
    "    logits = model(imgs).detach().cpu().numpy()\n",
    "    predictions = np.argmax(logits, axis=1)\n",
    "    odds = np.exp(logits)\n",
    "    confidences = np.max(odds, axis=1) / np.sum(odds, axis=1)\n",
    "    return predictions, confidences\n",
    "\n",
    "\n",
    "#\n",
    "# Load a model\n",
    "#\n",
    "# Model performance numbers are available at:\n",
    "#   https://github.com/huyvnphan/PyTorch_CIFAR10\n",
    "#\n",
    "\n",
    "model = resnet50(pretrained=True)\n",
    "model_name = \"resnet50\"\n",
    "\n",
    "#\n",
    "# Extract a few images to process\n",
    "#\n",
    "\n",
    "num_samples = 25\n",
    "batch_size = 5\n",
    "\n",
    "view = dataset.take(num_samples)\n",
    "\n",
    "image_paths, sample_ids = zip(*[(s.filepath, s.id) for s in view])\n",
    "data_loader = make_cifar10_data_loader(image_paths, sample_ids, batch_size)\n",
    "\n",
    "#\n",
    "# Perform prediction and store results in dataset\n",
    "#\n",
    "\n",
    "for imgs, sample_ids in data_loader:\n",
    "    predictions, confidences = predict(model, imgs)\n",
    "\n",
    "    # Add predictions to your FiftyOne dataset\n",
    "    for sample_id, prediction, confidence in zip(\n",
    "        sample_ids, predictions, confidences\n",
    "    ):\n",
    "        sample = dataset[sample_id]\n",
    "        sample[model_name] = fo.Classification(\n",
    "            label=classes[prediction],\n",
    "            confidence=confidence,\n",
    "        )\n",
    "        sample.save()\n",
    "\n",
    "#\n",
    "# Print the last batch of samples for which we added predictions\n",
    "#\n",
    "\n",
    "last_batch = dataset.select(sample_ids)\n",
    "print(last_batch.head(batch_size))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of samples: 25\n",
      "\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd82dfebeb022f4555f5',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/003270.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'horse', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': <Classification: {'label': 'horse', 'confidence': 0.8297524, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd84dfebeb022f457025',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/009974.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'airplane', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': <Classification: {'label': 'airplane', 'confidence': 0.7975642, 'logits': None}>,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd83dfebeb022f4560e9',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/006074.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'bird', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': <Classification: {'label': 'bird', 'confidence': 0.7952284, 'logits': None}>,\n",
      "}>\n"
     ]
    }
   ],
   "source": [
    "#\n",
    "# Get all samples for which we added predictions, in reverse order of\n",
    "# confidence\n",
    "#\n",
    "pred_view = (dataset\n",
    "    .exists(model_name)\n",
    "    .sort_by(\"%s.confidence\" % model_name, reverse=True)\n",
    ")\n",
    "\n",
    "print(\"Number of samples: %s\\n\" % len(pred_view))\n",
    "print(pred_view.head())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using the FiftyOne App\n",
    "\n",
    "FiftyOne provides a powerful App that allows you easily visualize,\n",
    "explore, search, filter, your datasets.\n",
    "\n",
    "You can explore the App interactively through the GUI, and you can even\n",
    "interact with it in real-time from your Python interpreter!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "App launched\n"
     ]
    }
   ],
   "source": [
    "# Launch the FiftyOne App\n",
    "session = fo.launch_app()\n",
    "\n",
    "# Open your dataset in the App\n",
    "session.dataset = dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![dataset](images/inference_1.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Show five random samples in the App\n",
    "session.view = dataset.take(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![limit](images/inference_2.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Show the samples for which we added predictions above\n",
    "session.view = pred_view"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![pred-view](images/inference_3.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Show the full dataset again\n",
    "session.view = None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![selected](images/inference_4.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can select images in the App by clicking on them. Then, you can hop back over to the library and make a view that contains those samples!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dataset:        my-dataset\n",
      "Num samples:    3\n",
      "Tags:           []\n",
      "Sample fields:\n",
      "    filepath:     fiftyone.core.fields.StringField\n",
      "    tags:         fiftyone.core.fields.ListField(fiftyone.core.fields.StringField)\n",
      "    metadata:     fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.metadata.Metadata)\n",
      "    ground_truth: fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.labels.Classification)\n",
      "    resnet50:     fiftyone.core.fields.EmbeddedDocumentField(fiftyone.core.labels.Classification)\n",
      "Pipeline stages:\n",
      "    1. Select(sample_ids=['5f21dd81dfebeb022f454930', '5f21dd81dfebeb022f454932', '5f21dd81dfebeb022f454931'])\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454930',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000001.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'cat', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': None,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454931',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000002.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'ship', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': None,\n",
      "}>\n",
      "<Sample: {\n",
      "    'dataset_name': 'my-dataset',\n",
      "    'id': '5f21dd81dfebeb022f454932',\n",
      "    'filepath': '/Users/Brian/fiftyone/cifar10/test/data/000003.jpg',\n",
      "    'tags': BaseList([]),\n",
      "    'metadata': None,\n",
      "    'ground_truth': <Classification: {'label': 'ship', 'confidence': None, 'logits': None}>,\n",
      "    'resnet50': None,\n",
      "}>\n"
     ]
    }
   ],
   "source": [
    "# Make a view containing the currently selected samples in the App\n",
    "selected_view = dataset.select(session.selected)\n",
    "\n",
    "# Print details about the selected samples\n",
    "print(selected_view)\n",
    "print(selected_view.head())"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
